package com.manda.smart.hub.common.sqlite;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.text.CharSequenceUtil;
import cn.hutool.core.util.TypeUtil;
import cn.hutool.db.Db;
import cn.hutool.db.Entity;
import lombok.Getter;

import javax.sql.DataSource;
import java.sql.SQLException;
import java.util.List;

/**
 * 表名称和列名称默认转下划线
 *
 * @author hongda.li
 */
@Getter
public class SqliteMapper<Bean> {

    private final Db runner;

    private final String tableName;

    private final Class<Bean> clazz;

    private final DataSource dataSource;

    @SuppressWarnings("unchecked")
    public SqliteMapper(DataSource dataSource) {
        this.dataSource = dataSource;
        this.runner = Db.use(this.dataSource);
        this.clazz = (Class<Bean>) TypeUtil.getTypeArgument(this.getClass());
        this.tableName = CharSequenceUtil.toUnderlineCase(this.clazz.getSimpleName());
    }

    public SqliteMapper(DataSource dataSource, Class<Bean> clazz) {
        this.clazz = clazz;
        this.dataSource = dataSource;
        this.runner = Db.use(this.dataSource);
        this.tableName = CharSequenceUtil.toUnderlineCase(this.clazz.getSimpleName());
    }

    public long count(Bean bean) {
        try {
            return this.runner.count(this.beanToEntity(bean));
        } catch (SQLException e) {
            throw new SqliteException(e);
        }
    }

    public Bean selectOne(Bean bean) {
        return CollUtil.getFirst(this.select(bean));
    }

    public List<Bean> select(Bean bean) {
        try {
            return this.runner.find(this.beanToEntity(bean), this.clazz);
        } catch (SQLException e) {
            throw new SqliteException(e);
        }
    }

    public List<Bean> select(String sql, Object... params) {
        try {
            return this.runner.query(sql, this.clazz, params);
        } catch (SQLException e) {
            throw new SqliteException(e);
        }
    }

    public List<Bean> selectAll() {
        try {
            return this.runner.find(Entity.create(this.tableName), this.clazz);
        } catch (SQLException e) {
            throw new SqliteException(e);
        }
    }

    public int insert(Bean bean) {
        try {
            return this.runner.insert(this.beanToEntity(bean));
        } catch (SQLException e) {
            throw new SqliteException(e);
        }
    }

    public int delete(Bean bean) {
        try {
            return this.runner.del(this.beanToEntity(bean));
        } catch (SQLException e) {
            throw new SqliteException(e);
        }
    }

    public int update(Bean bean, Bean where) {
        try {
            return this.runner.update(this.beanToEntity(bean), this.beanToEntity(where));
        } catch (SQLException e) {
            throw new SqliteException(e);
        }
    }

    public int execute(String sql, Object... params) {
        try {
            return this.runner.execute(sql, params);
        } catch (SQLException e) {
            throw new SqliteException(e);
        }
    }

    protected Entity beanToEntity(Bean bean) {
        return Entity.create(this.tableName).parseBean(bean, true, true);
    }
}
